package org.springblade.protocol.tcp.client;

import cn.hutool.core.util.HexUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * SocketClient
 * @author lijiamin
 */
public class SocketClient {

	private static Map<String, Channel> mapChannel = new HashMap<>(20);
	private static EventLoopGroup eventLoopGroup;
	private static Bootstrap bootstrap;

	/**
	 * send msg
	 * @param host
	 * @param msg
	 * @param type 1-string 2hex
	 */
	public static void sendMsg(String host, Integer port, String msg, Integer type) {
		System.out.println("send msg to client is : " + host + ":" + port + "   " + msg);
		Channel channel = mapChannel.get(host + ":" + port);
		if (channel == null) {
			return;
		}
		if (!channel.isActive()) {
			channel.close();
			return;
		}
		switch (type) {
			case 1:
				ByteBuf byteBuf = ByteBufUtil.encodeString(channel.alloc(), CharBuffer.wrap(msg), StandardCharsets.UTF_8);
				channel.writeAndFlush(byteBuf);
				break;
			case 2:
				channel.writeAndFlush(Unpooled.wrappedBuffer(HexUtil.decodeHex(msg)));
				break;
		}
	}

	public static void setOrDelServerChannel(String address, Channel channel) {
		mapChannel.put(address, channel);
	}

	static {
		eventLoopGroup = new NioEventLoopGroup(10);
		bootstrap = new Bootstrap();
		bootstrap.group(eventLoopGroup)
			.channel(NioSocketChannel.class)
			.option(ChannelOption.SO_RCVBUF, 1024 * 1024)
			.option(ChannelOption.SO_SNDBUF, 1024 * 1024)
			.option(ChannelOption.TCP_NODELAY, true)
			.option(ChannelOption.SO_KEEPALIVE, true)
			.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel socketChannel) throws Exception {
					socketChannel.pipeline().addLast(new IdleStateHandler(0, 60, 0, TimeUnit.SECONDS));
					socketChannel.pipeline().addLast(new SocketClientHandle());
				}
			});
	}

	/**
	 * 连接服务
	 * @param host
	 * @param port
	 */
	public static void connectServer(final String host, final int port) {
		Channel channel = mapChannel.get(host);
		if (channel != null) {
			channel.close();
		}
		bootstrap.remoteAddress(host, port).connect().addListener((ChannelFuture futureListener) -> {
			if (!futureListener.isSuccess()) {
				futureListener.channel().close();
				System.err.println(host + ":" + port + " connect error！！！！");
			} else {
				System.out.println(host + ":" + port + " connect succeed");
			}
		});
	}

}
